package com.paradox.aggregation.provider.juc;

import lombok.SneakyThrows;

import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.LockSupport;
import java.util.concurrent.locks.ReentrantLock;

public class MultiThreadTests {

    private static int num=0;
    private static Object objLock=new Object();

    private static ReentrantLock reentrantLock=new ReentrantLock();
    private static Condition conditionA=reentrantLock.newCondition();
    private static Condition conditionB=reentrantLock.newCondition();

    public static void main(String[] args) throws InterruptedException {
        ThreadA threadA=new ThreadA();
        ThreadB threadB=new ThreadB();
        threadA.setOneAnother(threadB);
        threadB.setOneAnother(threadA);

        threadA.start();
        threadB.start();
    }

    static class ThreadA extends Thread{
        private Thread oneAnother;

        public ThreadA(Thread oneAnother){
            this.oneAnother=oneAnother;
        }

        public void setOneAnother(Thread oneAnother) {
            this.oneAnother = oneAnother;
        }

        public ThreadA(){}

        /*@SneakyThrows
        @Override
        public void run() {
            synchronized (objLock){
                while(num<10){
                    if(num%2==0){
                        num++;
                        System.out.println(Thread.currentThread().getId()+":"+num);
                    }
                    objLock.notify();
                    objLock.wait();
                }
            }
        }*/

        /*@SneakyThrows
        @Override
        public void run() {
            try{
                reentrantLock.lock();
                while(num<100){
                    if(num%2==0){
                        num++;
                        System.out.println(Thread.currentThread().getId()+":"+num);
                    }
                    conditionB.signal();
                    conditionA.await();
                }
            }finally{
                reentrantLock.unlock();
            }
        }*/

        @SneakyThrows
        @Override
        public void run() {
            while(num<100){
                if(num%2==0){
                    num++;
                    System.out.println(Thread.currentThread().getId()+":"+num);
                    LockSupport.unpark(oneAnother);
                }
                LockSupport.park();
            }
            LockSupport.unpark(oneAnother);
        }
    }

    static class ThreadB extends Thread{
        private Thread oneAnother;
        public ThreadB(Thread oneAnother){
            this.oneAnother=oneAnother;
        }

        public void setOneAnother(Thread oneAnother) {
            this.oneAnother = oneAnother;
        }

        public ThreadB(){}

        /*@SneakyThrows
        @Override
        public void run() {
            synchronized (objLock){
                while(num<10){
                    if(num%2==1){
                        num++;
                        System.out.println(Thread.currentThread().getId()+":"+num);
                    }
                    objLock.notify();
                    if(num<10) objLock.wait();
                }
            }
        }*/

        /*@SneakyThrows
        @Override
        public void run() {
            try{
                reentrantLock.lock();
                while(num<100){
                    if(num%2==1){
                        num++;
                        System.out.println(Thread.currentThread().getId()+":"+num);
                    }
                    conditionA.signal();
                    if(num<100) conditionB.await();
                }
            }finally{
                reentrantLock.unlock();
            }
        }*/

        @SneakyThrows
        @Override
        public void run() {
            LockSupport.park();
            while(num<100){
                if(num%2==1){
                    num++;
                    System.out.println(Thread.currentThread().getId()+":"+num);
                    LockSupport.unpark(oneAnother);
                }
                LockSupport.park();
            }
            LockSupport.unpark(oneAnother);
        }
    }
}
